package com.frame.project.modules.test.testing.web;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.frame.project.modules.test.testing.entity.SysUser;

import de.odysseus.el.ExpressionFactoryImpl;
import de.odysseus.el.util.SimpleContext;

@RestController
@RequestMapping("/activitiHelloWorld")
public class ActivitiHelloWorldController {

	@Autowired
	ProcessEngine processEngine; //核心API,其他的类都是由他而来

	@Autowired
	ObjectMapper objectMapper; //jackson提供的,对象转换成为一个json字符串


	/**
	 * 部署流程
	 */
	@RequestMapping("/deployment")
	public void deployment(){
		Deployment deploy = processEngine.getRepositoryService() //与流程定义和部署相关的service
				.createDeployment() //创建一个部署对象
				.name("helloworld入门程序") //设置部署名称
				.addClasspathResource("processes/helloworld.bpmn")//从classpath的资源中加载,一次只能加载一个文件
				.addClasspathResource("processes/helloworld.png")
				.deploy(); //完成部署
		System.out.println(deploy.getId());    
		System.out.println(deploy.getName()); //部署的名称
	}

	/**
	 * 部署zip流程
	 */
	@RequestMapping("/deploymentZip")
	public void deploymentZip(){
		InputStream in = this.getClass().getClassLoader().getResourceAsStream("processes/helloworld.zip");
		ZipInputStream zipInputStream = new ZipInputStream(in);
		Deployment deploy = processEngine.getRepositoryService() //与流程定义和部署相关的service
				.createDeployment() //创建一个部署对象
				.name("helloworld入门程序") //设置部署名称
				.addZipInputStream(zipInputStream)//从zip文件部署
				.deploy(); //完成部署
		System.out.println(deploy.getId());    
		System.out.println(deploy.getName()); //部署的名称
	}


	/**
	 * 查询流程定义
	 */
	@RequestMapping("/findProcessDefinition")
	public void findProcessDefinition(){

		List<ProcessDefinition> list = processEngine.getRepositoryService()
				.createProcessDefinitionQuery() //创建流程定义查询(act_re_procdef表)
				//指定条件查询，where条件
				//.deploymentId("") //部署对象id查询
				//.processDefinitionId("")//流程定义id查询
				//.processDefinitionKey("") //流程定义key查询
				//.processDefinitionNameLike("")//流程定义名称，模糊查询
				/** 排序*/
				.orderByProcessDefinitionVersion().desc() //流程版本  降序排序
				//.orderByProcessDefinitionName().desc() //流程定义名称 降序排序
				/** 返回结果集  */
				.list(); //返回一个集合，封装流程定义
		//.singleResult() //返回唯一结果集
		//.count() //返回结果数量

		for (ProcessDefinition processDefinition : list) {
			System.out.println("流程定义ID:"+processDefinition.getId());  //流程定义的key+版本+随机数
			System.out.println("流程定义名称:"+processDefinition.getName()); //流程图name属性
			System.out.println("流程定义的key:"+processDefinition.getKey()); //流程图id属性
			System.out.println("流程定义的版本:"+processDefinition.getVersion());
			System.out.println("资源名称bpmn文件:"+processDefinition.getResourceName());
			System.out.println("资源名称png文件:"+processDefinition.getDiagramResourceName());
			System.out.println("部署对象ID:"+processDefinition.getDeploymentId());
			System.out.println("#################################");
		}
	}


	/**
	 * 流程图key查找最新流程图所有节点
	 */
	@RequestMapping("/findProcessNode/{key}")
	public void findProcessNode(@PathVariable("key")String key){
		List<ProcessDefinition> singleResult = processEngine.getRepositoryService().createProcessDefinitionQuery().processDefinitionKey(key)
				.orderByProcessDefinitionVersion().desc().list();
		if(singleResult != null) {
			//取最新流程图
			BpmnModel model = processEngine.getRepositoryService().getBpmnModel(singleResult.get(0).getId());
			if(model != null) {    
				Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();   
				for(FlowElement e : flowElements) {       
					System.out.println("flowelement id:" + e.getId() + "  name:" + e.getName() + "   class:" + e.getClass().toString());  
				}
			}
		}

	}



	/**
	 * 删除流程定义
	 */
	@RequestMapping("/deleteProcessDefinition/{deploymentId}")
	public void deleteProcessDefinition(@PathVariable("deploymentId")String deploymentId){

		/**
		 * 不带联级删除
		 * 注意：只能删除没有启动的流程，如果流程启动则删除报错
		 */
		/*processEngine.getRepositoryService()
		  				.deleteDeployment(deploymentId);*/
		/**
		 * 级联删除，默认为false
		 *注意： 不管流程是否启动，都会删除
		 */
		processEngine.getRepositoryService()
		.deleteDeployment(deploymentId,true);
		System.out.println("删除成功");

	}


	/**
	 * 查看流程图
	 * @throws IOException 
	 */
	@RequestMapping("/viewPic/{deploymentId}")
	public void viewPic(@PathVariable("deploymentId")String deploymentId,
			HttpServletRequest request,HttpServletResponse response) throws IOException{

		/**
		 * 获取流程名称 
		 */
		List<String> deploymentResourceNames = processEngine.getRepositoryService()
				.getDeploymentResourceNames(deploymentId);
		String resourceName = "";
		for (String name : deploymentResourceNames) {
			if(name.indexOf(".png") >= 0) {
				resourceName = name;
			}
		}
		InputStream in = processEngine.getRepositoryService()
				.getResourceAsStream(deploymentId, resourceName);



		byte[] byteArray = IOUtils.toByteArray(in);
		ServletOutputStream outputStream = response.getOutputStream();
		outputStream.write(byteArray);
		outputStream.flush();
		outputStream.close();
	}


	/**
	 * 追踪流程图节点位置
	 * @param procInstId  流程实例id
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	@RequestMapping("/viewPicZ/{procInstId}")
	public void viewPicZ(@PathVariable("procInstId")String procInstId,
			HttpServletRequest request,HttpServletResponse response) throws IOException{

		/**
		 * 流程图乱码就用这个方法
		 */
		ProcessInstance pi = processEngine.getRuntimeService().createProcessInstanceQuery()
				.processInstanceId(procInstId).singleResult();
		BpmnModel bpmnModel = this.processEngine.getRepositoryService().getBpmnModel(pi.getProcessDefinitionId());
		List<String> activeIds = this.processEngine.getRuntimeService().getActiveActivityIds(pi.getId());
		ProcessDiagramGenerator p = new DefaultProcessDiagramGenerator();
		InputStream  in = p.generateDiagram(bpmnModel, "png", activeIds, Collections.<String> emptyList(), "宋体", "宋体"
				,null, null, 1.0);

		byte[] byteArray = IOUtils.toByteArray(in);
		ServletOutputStream outputStream = response.getOutputStream();
		outputStream.write(byteArray);
		outputStream.flush();
		outputStream.close();
	}



	/**
	 * 版本查看：  查看最新版本流程
	 * @throws IOException 
	 */
	@RequestMapping("/findLastVersionProcessDefinition")
	public void findLastVersionProcessDefinition(){
		List<ProcessDefinition> list = processEngine.getRepositoryService()
				.createProcessDefinitionQuery()
				.orderByProcessDefinitionVersion().asc()  //流程版本升序排序
				.list();
		Map<String, ProcessDefinition> map = new LinkedHashMap<>();
		for (ProcessDefinition pd : list) {
			map.put(pd.getKey(), pd);
		}
		List<ProcessDefinition> arrayList = new ArrayList<>(map.values());
		for (ProcessDefinition processDefinition : arrayList) {
			System.out.println("流程定义ID:"+processDefinition.getId());  //流程定义的key+版本+随机数
			System.out.println("流程定义名称:"+processDefinition.getName()); //流程图name属性
			System.out.println("流程定义的key:"+processDefinition.getKey()); //流程图id属性
			System.out.println("流程定义的版本:"+processDefinition.getVersion());
			System.out.println("资源名称bpmn文件:"+processDefinition.getResourceName());
			System.out.println("资源名称png文件:"+processDefinition.getDiagramResourceName());
			System.out.println("部署对象ID:"+processDefinition.getDeploymentId());
			System.out.println("#################################");
		}
	}



	/**
	 * 版本删除：  删除流程(删除key相同的所有不同版本的流程定义)
	 * @throws IOException 
	 */
	@RequestMapping("/deleteProcessDefinitionByKey/{key}")
	public void deleteProcessDefinitionByKey(@PathVariable("key")String key){
		/**
		 * 查出当前key值相同的所有流程
		 */
		List<ProcessDefinition> list = processEngine.getRepositoryService()
				.createProcessDefinitionQuery()
				.processDefinitionKey(key)
				.list();
		/**
		 * 遍历删除
		 */
		for (ProcessDefinition processDefinition : list) {
			processEngine.getRepositoryService()
			.deleteDeployment(processDefinition.getDeploymentId(),true);
		}

	}






	/**
	 * 启动流程实例
	 */
	@RequestMapping("/start")
	public void start(){
		ProcessInstance processInstance = processEngine.getRuntimeService() //与正在执行的流程实例和执行对象相关的service
				.startProcessInstanceByKey("helloworld"); //使用流程定义的key启动流程实例，key对应的是流程图中的id属性,默认按照最新流程版本启动。
		System.out.println("流程实例id:"+processInstance.getId());//流程实例id
		System.out.println("流程定义id"+processInstance.getProcessDefinitionId()); //流程定义id
	}

	/**
	 * 查询当前人的任务
	 */
	@RequestMapping("/findMyPersonaiTask/{taskAssignee}")
	public void findMyPersonaiTask(@PathVariable("taskAssignee")String taskAssignee){
		List<Task> list = processEngine.getTaskService() //与正在执行的任务相关的service
				.createTaskQuery()  //创建任务查询对象
				.taskAssignee(taskAssignee) //指定办理人
				.list();
		for (Task task : list) {
			System.out.println("任务id:"+task.getId());
			System.out.println("任务名称:"+task.getName());
			System.out.println("任务创建时间:"+task.getCreateTime());
			System.out.println("任务的办理人:"+task.getAssignee());
			System.out.println("流程实例id:"+task.getProcessInstanceId());
			System.out.println("执行对象id:"+task.getExecutionId());
			System.out.println("流程定义id:"+task.getProcessDefinitionId());
		}
	}


	/**
	 * 完成我的任务
	 */
	@RequestMapping("/completeMyPersonaiTask/{id}")
	public void completeMyPersonaiTask(@PathVariable("id")String taskId){
		processEngine.getTaskService()
		.complete(taskId);
		System.out.println("完成任务,任务id:"+taskId);

	}


	/**
	 * 查询流程状态(判断流程是否已结束)
	 */
	@RequestMapping("/isProcessEnd/{processInstanceId}")
	public void isProcessEnd(@PathVariable("processInstanceId")String processInstanceId){
		ProcessInstance singleResult = processEngine.getRuntimeService()
				.createProcessInstanceQuery()
				.processInstanceId(processInstanceId)
				.singleResult();
		if(singleResult != null) {
			System.out.println("流程没结束");
		}else {
			System.out.println("流程已结束");
		}
	}

	/**
	 * 查询历史任务  act_hi_taskinst表
	 */
	@RequestMapping("/findHistoricTask/{taskAssignee}")
	public void findHistoricTask(@PathVariable("taskAssignee")String taskAssignee){
		/*List<HistoricTaskInstance> list = processEngine.getHistoryService()
				.createHistoricTaskInstanceQuery() //创建历史任务实例查询
				//.taskAssignee(taskAssignee)  //办理人
				.processInstanceId(taskAssignee) //流程实例查询
				.list();
		for (HistoricTaskInstance ht : list) {
			System.out.println("办理人名称："+ht.getAssignee()+","+"节点名称："+ht.getName());
		}*/
		 processEngine.getHistoryService()
			.createHistoricTaskInstanceQuery()
			.processInstanceId("42517").singleResult();
	}


	/**
	 * 查询历史流程实例  act_hi_procinst表
	 */
	@RequestMapping("/findHistoricProcessInstance/{processInstanceId}")
	public void findHistoricProcessInstance(@PathVariable("processInstanceId")String processInstanceId){
		HistoricProcessInstance singleResult = processEngine.getHistoryService()
				.createHistoricProcessInstanceQuery()//创建历史流程实例
				.processInstanceId(processInstanceId) //流程实例查询
				.singleResult();
		System.out.println(singleResult.getId()+","+singleResult.getStartActivityId()+","+singleResult.getEndActivityId());
	}



	/**
	 * 查询历史变量  act_hi_varinst表
	 */
	@RequestMapping("/findHistoricVarinst/{processInstanceId}")
	public void findHistoricVarinst(@PathVariable("processInstanceId")String processInstanceId){
		List<HistoricVariableInstance> list = processEngine.getHistoryService()
				.createHistoricVariableInstanceQuery()//创建历史变量实例
				.processInstanceId(processInstanceId) //流程实例查询
				.orderByVariableName().desc().list();

		for (HistoricVariableInstance variableInstance : list) {
			Object value = variableInstance.getValue();
			System.out.println(variableInstance.getId()+","+
					variableInstance.getVariableName()+","+
					(value instanceof SysUser ? (SysUser)value  : value)
					);
		}
	}


	/**
	 * 查询历史活动  act_hi_actinst表
	 */
	@RequestMapping("/findHistoricActiviti/{processInstanceId}")
	public void findHistoricActiviti(@PathVariable("processInstanceId")String processInstanceId){
		List<HistoricActivityInstance> list = processEngine.getHistoryService()
				.createHistoricActivityInstanceQuery()//创建历史活动实例
				.processInstanceId(processInstanceId) //流程实例查询
				.orderByHistoricActivityInstanceStartTime().asc()
				.list();
		for (HistoricActivityInstance activityInstance : list) {
			System.out.println(activityInstance.getId()+","+activityInstance.getActivityId()+","+activityInstance.getActivityName());
		}

	}



	/**
	 * 设置流程变量,act_ru_variable表
	 */
	@RequestMapping("/setVariables/{taskId}")
	public void setVariables(@PathVariable("taskId")String taskId){
		//流程任务service
		TaskService taskService = processEngine.getTaskService();
		//1.设置流程变量，使用基本数据类型
		//		taskService.setVariableLocal(taskId, "请假天数",3); //与任务id绑定
		//		taskService.setVariable(taskId, "请假日期",new Date()); //与任务id绑定
		//		taskService.setVariable(taskId, "请假原因","回家探亲"); //与任务id绑定

		//2.设置流程变量，使用javaBean
		SysUser user = new SysUser();
		user.setId("111");
		user.setName("管理员张三");
		user.setPwd("123456");
		taskService.setVariable(taskId, "人员信息",user); 

	}

	/**
	 * 获取流程变量,act_ru_variable表
	 */
	@RequestMapping("/getVariables/{taskId}")
	public void getVariables(@PathVariable("taskId")String taskId){
		//流程任务service
		TaskService taskService = processEngine.getTaskService();
		//1.获取流程变量
		//		Object days = taskService.getVariable(taskId, "请假天数"); 
		//		Object date = taskService.getVariable(taskId, "请假日期");
		//		Object resean = taskService.getVariable(taskId, "请假原因"); 
		//		System.out.println("请假天数:"+days);
		//		System.out.println("请假日期:"+date);
		//		System.out.println("请假原因:"+resean);
		//2.javaBean获流程变量
		SysUser user = (SysUser)taskService.getVariable(taskId, "人员信息"); 
		System.out.println(user.toString());
	}


	/**
	 * 设置与获取流程变量的场景,act_ru_variable表
	 */
	@RequestMapping("/setAndGetVariables")
	public void setAndGetVariables(){
		/*流程实例，执行对象(流程启动)*/
		RuntimeService runtimeService = processEngine.getRuntimeService();
		/*流程任务service*/
		TaskService taskService = processEngine.getTaskService();
		/*设置流程变量*/
		//runtimeService.startProcessInstanceByKey(ProcessDefinitionKey, Map) //启动流程实例，可以设置流程变量，map集合
		//runtimeService.setVariable(executionId, variableName,value); //表示使用执行对象ID,和流程变量的名称，设置流程的值(一次只能设置一个值)
		//runtimeService.setVariables(executionId, Map); //表示使用执行对象ID,和map集合设置流程变量，map中的key事流程变量名称，value是值

		//taskService.setVariable(taskId, variableName, value); //表示使用执行对象ID,和流程变量的名称，设置流程的值(一次只能设置一个值)
		//taskService.setVariables(taskId, Map); //表示使用执行对象ID,和map集合设置流程变量，map中的key事流程变量名称，value是值
		//taskService.complete(taskId, Map); //完成任务，也可以设置变量

		/* 获取流程变量*/
		//runtimeService.getVariable(executionId, variableName);// 使用执行对象id和流程变量名称，获取流程变量值
		//runtimeService.getVariables(executionId); // 使用执行对象id,获取所有流程变量名称和值，返回到Map中
		//runtimeService.getVariables(executionId, List<variableName>) //使用执行对象id和流程变量名称集合，返回指定流程变量名和值到Mao中

		//taskService.getVariable(taskId, variableName);// 使用任务id和流程变量名称，获取流程变量值
		//taskService.getVariables(taskId); // 使用任务id,获取所有流程变量名称和值，返回到Map中
		//taskService.getVariables(taskId, List<variableName>) //使用任务id和流程变量名称集合，返回指定流程变量名和值到Mao中
	}



}
